// Copyright 2011, Vanya Davidenko.
// Используемая кодировка: UTF-8.
 
#include <opencv2/opencv.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <windows.h>
#include <utility>

#include "mouse_control.h"
#include "cam_control.h"



namespace cvhi {

struct MouseCallbackContext {
    int width;
    int height;
    cv::Point tl;
    cv::Point br;
};

void myMouseCallback(int event, int x, int y, int /*flags*/, void* void_context)
{
    MouseCallbackContext* context = (MouseCallbackContext*)(void_context);

    switch( event ) {
        case CV_EVENT_LBUTTONDOWN:
            context->tl.x = x;
            context->tl.y = y;
            context->br.x = x;
            context->br.y = y;
            break;
            
        case CV_EVENT_LBUTTONUP:
            context->tl.x = -1;
            context->tl.y = -1;
            context->br.x = -1;
            context->br.y = -1;
            break;

        case CV_EVENT_MOUSEMOVE: 
            context->br.x = x > 50000 ? 0 : ::std::min(x, context->width);
            context->br.y = y > 50000 ? 0 : ::std::min(y, context->height);
            break;
    }
}


bool isCorrectRectangle(const cv::Rect rect) {
    return  rect.x != -1 && rect.width > 0 && rect.height > 0;
}


int Main() {
    const int width = 1280;
    const int height = 720;
    const int fps = 30;

    cv::VideoWriter avi_writer("1.avi", CV_FOURCC('X', 'V', 'I', 'D'), 
                               fps/2, cv::Size(width, height));

    assert(CamControl::listDevices() > 0);
    CamControl cam(0, width, height, fps, false, true);
    cam.setAutoFocus(false);
    cam.setAutoExposure(true);
    cam.setSettings(VideoProcAmp_Brightness, 1);

    const CvSize sz = cvSize(cam.width(), cam.height());
    cv::Mat frame(cvCreateImage(sz, IPL_DEPTH_8U, 3));

    const char* window_name = "video";
    cv::namedWindow(window_name, 1);

    MouseCallbackContext mouse_context;
    mouse_context.height = cam.height();
    mouse_context.width = cam.width();
    mouse_context.tl.x = -1;
    mouse_context.tl.y = -1;
    mouse_context.br.x = -1;
    mouse_context.br.y = -1;
    cvSetMouseCallback(window_name, myMouseCallback, &mouse_context);

    for ( ; ; ) {
        if ( cam.isFrameNew() ) {
            cam.getPixels(frame.data);

            const cv::Rect active_rect(mouse_context.tl, mouse_context.br);
            if ( isCorrectRectangle(active_rect) ) {
                cv::rectangle(frame, active_rect, CV_RGB(0, 200, 0), 1);

                cv::Mat roi = frame(active_rect);

                const float kernel_init[] = { -0.1f, -0.1f, -0.1f,
                                              -0.1f, 2.f, -0.1f,
                                              -0.1f, -0.1f, -0.1f };

                cv::Mat kernel(cv::Size(3,3), CV_32FC1, (void*)kernel_init);
                cv::filter2D(roi, roi, -1, kernel);
            }

            cv::imshow(window_name, frame);
            avi_writer.write(frame);
        }


        switch ( int c = cvWaitKey(30) ) {
            case 27: return 0;
            case 'w':
            case 'W': {
                const CamControl::Settings focus = cam.getFocusSettings();    
                cam.setFocus(focus.cur + focus.step);
                break;
            }
            case 's':
            case 'S': {
                const CamControl::Settings focus = cam.getFocusSettings();    
                cam.setFocus(focus.cur - focus.step);
                break;
            }
            case 'q':
            case 'Q': cam.setAutoFocus(true); break;
            case 'a':
            case 'A': cam.setAutoFocus(false); break;


            case 'u':
            case 'U': {
                const CamControl::Settings exp = cam.getExposureSettings();    
                cam.setFocus(exp.cur + exp.step);
                break;
            }
            case 'j':
            case 'J': {
                const CamControl::Settings exp = cam.getExposureSettings();    
                cam.setExposure(exp.cur - exp.step);
                break;
            }
            case 'y':
            case 'Y': cam.setAutoExposure(true); break;
            case 'h':
            case 'H': cam.setAutoExposure(false); break;


            case 'z':
            case 'Z': {
                const CamControl::Settings zoom = cam.getZoomSettings();
                cam.setZoom(zoom.cur + zoom.step);
            }
            case 'x':
            case 'X': {
                const CamControl::Settings zoom = cam.getZoomSettings();
                cam.setZoom(zoom.cur - zoom.step);
            }

            case ' ': cam.showSettingsWindow();
        }
    }
}

}  // cvhi


int main() {
    return cvhi::Main();
}